QUESTION: Where and when are SHS in Apra Harbor?

AIMS: Analyse and plot SHS eDNA detections in Blue Hole, Inner Harbor, Middle Shoals, Orote Point and Sasa Bay over the period of Feb 2019 to July 2020.

## LOAD LIBRARIES ----
library(zoo) ## as.yearmon
library(ggmap) ## maps
library(ggsn) ## scale bar
library(viridis) ## colour blind friendly colour scale
library(ggspatial) ## north arrow
library(mgcv) ## GAM
library(gratia) ## as above
library(mgcViz) ## gam diagnostics
library(ggpubr) ## ggarrange
library(tidyverse) ## load last
## IMPORT SHS SURVEY DATA ----

## colour scheme
# scales::show_col(viridis(5))
# scales::show_col(viridis(5, alpha=.8))
# scales::show_col(viridis(4, alpha=.8, option="B"))

## import qPCR results (as confirmed by sanger sequencing)
SHS_data_unmod <- read.csv("docs/00.1_confirmed_detection_data.csv")

## import field sample data (including eDNA concentration)
SHS_field_sample_data_unmod <- read.csv("docs/00.2_field_sample_data.csv")

## CALCULATE PROPORTIONS ----

## calculate the proportion of technical replicates amplified per biological replicate (eDNA sample)
## and the proportion of biological replicates (eDNA samples) amplified per site
SHS_data<-SHS_data_unmod %>%
  ## group by month, site and sample
  group_by(field_collection_month, site, sample) %>% 
  ## add a column containing the tech rep number 
  mutate(tech_rep_no = row_number()) %>%
  ## add an unweighted tally of the number of rows per sample
  ## i.e. the number of tech reps run per sample
  add_tally(name="no_tech_reps_run_per_sample") %>% 
  ## add a weighted tally of the number of rows with a positive result
  ## i.e. the number of tech reps amplified per sample
  add_tally(name="no_tech_reps_ampd_per_sample", wt=positive) %>% 
  ## calculate the  prop of tech reps amplified per sample
  mutate(prop_tech_reps_ampd_per_sample = 
           1/no_tech_reps_run_per_sample*no_tech_reps_ampd_per_sample) %>%
  ## calculate the same information for biological replicates
  left_join(., SHS_data_unmod %>%
              ## select only necessary information
              select(sample, field_collection_month, site, positive) %>%
              ## filter out blanks
              filter(!grepl('E', sample)) %>%
              ## retain only unique rows (removes rows where more than 1 tech rep amp'd)
              unique(.) %>%
              ## group by month and site
              group_by(field_collection_month, site) %>%
              ## add a weighted tally of the number of rows per month/site w positive results
              ## i.e. the number of biological reps amplified per sample
              add_tally(name="no_bio_reps_ampd_per_site", wt=positive) %>%
              ## remove positive column (because it differs between bio reps)
              select(-positive) %>%
              ## retain only unique rows (removes rows where info differs within sample)
              unique(.) %>%
              ## add an unweighted tally of the number of rows per site
              ## i.e. the number of biological reps collected per site
              add_tally(name="no_bio_reps_collected_per_site") %>%
              ## calculate the prop of biological reps amplified per site
              mutate(prop_bio_reps_ampd_per_site =
                       1/no_bio_reps_collected_per_site*no_bio_reps_ampd_per_site),
            ## specify columns to join by
            by = c("sample", "field_collection_month", "site")) 

## MERGE DETECTIONS AND SAMPLE DATA AND ADD TIME OF YEAR INFO ----
SHS_data_full <- left_join(SHS_data, SHS_field_sample_data_unmod, 
                           by = c("sample", "field_collection_month", "site"="site_name")) %>%
  ## rename dat column
  rename(date_collected=date) %>%
  ## ungroup data
  ungroup(.) %>%
  ## format field collection month column
  mutate(field_collection_month = as.yearmon(field_collection_month)) %>%
  ## arrange rows by field collection month column values
  arrange(., field_collection_month) %>%
  ## add and format extra date information columns
  mutate(fc_month_factor = fct_inorder(factor(field_collection_month)),
         fc_month_number = as.numeric(factor(field_collection_month)),
         calendar_month = format(as.yearmon(field_collection_month), "%B"),
         calendar_month_number = as.numeric(format(field_collection_month, "%m")),
         fc_month_number_cyclic = ifelse(calendar_month_number > 2,
                                    calendar_month_number-2,
                                    calendar_month_number+10),
         ## add seasons to data frame (dry = December to May, wet = June to November)
         season = ifelse(grepl("Dec", field_collection_month), "wet", 
                         ## Dec = transitional month
                    ifelse(grepl("Jan", field_collection_month), "dry",
                      ifelse(grepl("Feb", field_collection_month), "dry",
                        ifelse(grepl("Mar", field_collection_month), "dry",
                          ifelse(grepl("Apr", field_collection_month), "dry",
                            ifelse(grepl("May", field_collection_month), "dry",
                              ifelse(grepl("Jun", field_collection_month), "dry", 
                                     ## Jun = transitional month
                                ifelse(grepl("Jul", field_collection_month), "wet",
                                  ifelse(grepl("Aug", field_collection_month), "wet",
                                    ifelse(grepl("Sep", field_collection_month), "wet",
                                      ifelse(grepl("Oct", field_collection_month), "wet",
                                ifelse(grepl("Nov", field_collection_month), "wet",
                                                 "None")))))))))))),
         season_factor = factor(season)) %>%
  ## arrange data by calendar month number
  arrange(., calendar_month_number) %>%
  ## reorder factor levels by first appearance
  mutate(calendar_month_factor = fct_inorder(factor(calendar_month))) %>%
  ## rename "positive" column to indicate tech rep was positive
  rename(positive_tech = positive) %>%
  ## add a positive bio column to indicate bio rep is considered positive
  mutate(positive_bio = ifelse(no_tech_reps_ampd_per_sample > 0, 1, 0)) %>%
  ## start mid year
  mutate(calendar_month_factor_mid = factor(calendar_month_factor, 
                                        levels = c("July", "August", "September",
                                                   "October", "November", "December",
                                                   "January" , "February", "March",
                                                   "April", "May", "June")))

## export it
write.csv(SHS_data_full, "docs/01.0_SHS_data_full.csv", row.names = FALSE)

## extract all points (where recorded) for filter sample each site/month
sampling_points<-SHS_field_sample_data_unmod %>%
  filter(latitude!="NA" | longitude!="NA") %>% 
  filter(latitude<13.48) %>% # blue hole point not at blue hole
  mutate(field_collection_month=as.yearmon(field_collection_month)) %>%
  select(site_name, field_collection_month, sample_no, latitude, longitude)

## extract points for first filter sample each site/month
first_sampling_points <- sampling_points %>%
  filter(., sample_no == "1") # retain only first sample (and GPS point for that sample)

## export them 
write.csv(sampling_points, "docs/01.1_sampling_points.csv", row.names = FALSE)
write.csv(first_sampling_points , "docs/01.2_first_sampling_points.csv", row.names = FALSE)
## IMPORT LIBRARIES AND MAP DATA ----

## provide ggmap with your key
# register_google(key = "[your key here]") 

## create data frame for site locations
SHS_sites <- cbind.data.frame(site=c("Inner Harbor", "Sasa Bay", "Middle Shoals", 
                                     "Orote Point", "Blue Hole"), 
                              m_latitude=c(13.43181, 13.44769, 13.44959, 
                                         13.44947, 13.43627),
                              m_longitude=c(144.67573, 144.67537, 144.65729, 
                                          144.62466, 144.62741))

## FORMAT SHS SURVEY DATA FOR MAP ----

## create data frame with site-level detection data (relevant to map) only
SHS_figure_map_data <- SHS_data_full %>%
  ## add site locations to full data set
  left_join(., SHS_sites, by="site") %>%
  ## retain only information related to biological replicates (samples)
  select(field_collection_month, date_collected,
         site, m_latitude, m_longitude, calendar_month_factor,
         calendar_month_factor_mid, calendar_month_number,
         sample_less, prop_bio_reps_ampd_per_site, 
         no_bio_reps_ampd_per_site, season) %>%
  ## filter out blanks
  filter(!grepl('E', sample_less)) %>%
  ## keep only unique rows (remove tech rep info)
  unique(.) %>%
  ## group by month and site
  group_by(calendar_month_factor, site) %>%
  ## calculate mean proportion of biological replicates amplified 
  ## (because we sampled May and July of 2019 an 2020)
  mutate(mean_prop_bio_amps = mean(prop_bio_reps_ampd_per_site), 
         mean_no_bio_amps = ceiling(mean(no_bio_reps_ampd_per_site)),
         ## specify the shape is an "x" if 0 and a "circle" if else
         shapes = if_else(mean_no_bio_amps == 0, "4", "21"), 
         ## specify label as nothing if 0 and the proportion rounded to 1 digit if else
         labels = if_else(mean_no_bio_amps == 0, " ", 
                          paste(mean_no_bio_amps))) %>%
  ## remove duplicate month, year and sample info
  select(-prop_bio_reps_ampd_per_site, -no_bio_reps_ampd_per_site,
         -field_collection_month, -date_collected, -sample_less) %>%
  unique(.) %>%
  ## for scale_bar
  mutate(long = m_longitude, lat = m_latitude)

## MAKE A MAP ----

# ## Find latitudes and longitudes to be centre of distribution map
# mean(SHS_sites$m_latitude) # 13.44297
# mean(SHS_sites$m_longitude) # 144.6521

## create map style at https://mapstyle.withgoogle.com/
s2<- "style=element:geometry%7Ccolor:0xf5f5f5&style=element:labels%7Cvisibility:off&style=element:labels.icon%7Cvisibility:off&style=element:labels.text.fill%7Ccolor:0x616161&style=element:labels.text.stroke%7Ccolor:0xf5f5f5&style=feature:administrative%7Celement:geometry%7Cvisibility:off&style=feature:administrative.land_parcel%7Cvisibility:off&style=feature:administrative.land_parcel%7Celement:labels.text.fill%7Ccolor:0xbdbdbd&style=feature:administrative.neighborhood%7Cvisibility:off&style=feature:poi%7Cvisibility:off&style=feature:poi%7Celement:geometry%7Ccolor:0xeeeeee&style=feature:poi%7Celement:labels.text.fill%7Ccolor:0x757575&style=feature:poi.park%7Celement:geometry%7Ccolor:0xe5e5e5&style=feature:poi.park%7Celement:labels.text.fill%7Ccolor:0x9e9e9e&style=feature:road%7Cvisibility:off&style=feature:road%7Celement:geometry%7Ccolor:0xffffff&style=feature:road%7Celement:labels.icon%7Cvisibility:off&style=feature:road.arterial%7Celement:labels.text.fill%7Ccolor:0x757575&style=feature:road.highway%7Celement:geometry%7Ccolor:0xdadada&style=feature:road.highway%7Celement:labels.text.fill%7Ccolor:0x616161&style=feature:road.local%7Celement:labels.text.fill%7Ccolor:0x9e9e9e&style=feature:transit%7Cvisibility:off&style=feature:transit.line%7Celement:geometry%7Ccolor:0xe5e5e5&style=feature:transit.station%7Celement:geometry%7Ccolor:0xeeeeee&style=feature:water%7Celement:geometry%7Ccolor:0xc9c9c9&style=feature:water%7Celement:labels.text.fill%7Ccolor:0x9e9e9e&size=480x360"

## get a Google map of Apra Harbor (retrieves raster map from Google Maps)
## Note that in most cases by using this function you are agreeing to the Google Maps API Terms of Service at https://cloud.google.com/maps-platform/terms/ **
ApraHarbor <- get_googlemap(center = c(lon = 144.6521, lat = 13.44297), 
                zoom = 13, 
                maptype = 'terrain',
                color = 'bw',
                style = s2)

## use ggmap to plot the the raster using the ggplot2 framework
ggmap(ApraHarbor)


## add SHS survey information to plot
map1.0 <- ggmap(ApraHarbor, extent = "panel") +
  ## specify the aesthetics of the "bubbles" on the plot
  geom_point(aes(x = m_longitude, y = m_latitude, 
                 fill = site,
                 size = mean_no_bio_amps, shape = shapes), 
             data = SHS_figure_map_data,
             alpha = 0.6, 
             stroke = 0.6) +
  ## customise the size
  scale_size(range = c(2, 12), guide = "none") + 
  ## customise the shape so that 0 values are "x"
  scale_shape_manual(values=c(21, 4), guide = "none") +
  # limit the size of the plot (produces message, ignore it)
  scale_x_continuous(limits = c(144.615, 144.69), expand = c(0, 0)) +
  scale_y_continuous(limits = c(13.415, 13.47), expand = c(0, 0)) +
  xlab("Longitude")+
  ylab("Latitude")+
  ## facet the plot by month (n=2 for May and July)
  facet_wrap(~ calendar_month_factor_mid, ncol = 3) +
  ## move the legend and edit the facet strip panels
  theme(legend.position="bottom", 
        strip.background = element_blank(), 
        panel.border = element_rect(colour = "gray30", fill = NA),
        strip.text.x = element_text(margin = margin(0.1, 0, 0.1, 0, "cm"))) +
  ## make it colour blind friendly
  scale_fill_viridis(discrete=TRUE) +
  ## edit legend appearance
  guides(fill = guide_legend(override.aes = list(shape = 21,
                                                 size = 5), 
                                                 title = "Site")) +
  ## add labels to "bubbles"
  geom_text(aes(x = m_longitude, y = m_latitude, 
                label = labels, 
                size = 0.1),
            data = SHS_figure_map_data)

# map1.0

# plot.new() ## use this if you get an error below

## add a scale bar
map1.2 <- map1.0 + scalebar(data = SHS_figure_map_data,
                            dist=0.5, # distance to represent each segment of the scale bar 
                            dist_unit="km", # unit of measurement for dist
                            transform=TRUE, # TRUE = decimal degrees, FALSE = m
                            model = 'WGS84', # choice of ellipsoide model (where transorm=TRUE)
                            border.size = 0.2,
                            box.color = "grey30",
                            box.fill = c("grey80", "white"),
                            st.size = 2, ## scale bar size 
                            height = 0.09, ## height as proportion of the y-axis (0-1)
                            location = "bottomright", ## scale bars location in the plot
                            anchor = c(x=144.688,y=13.417), ## for corner of location
                            st.dist = 0.1, ## distance bw scale bar and text
                            alpha = 0 ## make the text see-through
                            ) 
# map1.2

## add north arrow
map1.3 <- map1.2 +  
  annotation_north_arrow(height = unit(0.25, "cm"),
                         width = unit(0.25,"cm"),
                         location = "tl", ## top left
                         pad_x = unit(0.25, "cm"),
                         pad_y = unit(0.25, "cm"),
                         style = north_arrow_orienteering(
                           line_width = 1,
                           line_col = "gray50",
                           fill = c("gray80", "white"),
                           text_col = NA, ## removes text?
                           text_family = "",
                           text_face = NULL,
                           text_size = 0,
                           text_angle = 0))
map1.3

## save it
ggsave("docs/figure_detect.tiff", plot=map1.3, device="tiff", width=21/1.2, height=28/1.2, units="cm", dpi=500)
## FORMAT SHS DATA FOR BUBBLE PLOT MODEL ----
## create data frame with site-level detection data (relevant to model) only
SHS_bubble_data <- SHS_data_full %>%
  ## filter out blanks
  filter(!grepl('E', sample_less)) %>%
  ## retain only information at the site-level
  select(field_collection_month, fc_month_factor, fc_month_number,
         fc_month_number_cyclic, calendar_month, calendar_month_factor,
         calendar_month_factor_mid, calendar_month_number, date_collected, 
         site, season, season_factor, prop_bio_reps_ampd_per_site, 
         no_bio_reps_ampd_per_site, no_bio_reps_collected_per_site) %>%
  ## keep only unique rows (remove tech rep info)
  unique(.) %>%
  mutate(site_factor=factor(site)) %>%
  ## create new calendar month number column 
  mutate(calendar_month_number_mid = as.numeric(calendar_month_factor_mid))

## export it
write.csv(SHS_bubble_data, "docs/01.3_SHS_bubble_data.csv", row.names = FALSE)

## MODEL DATA WITH GAM ----
gam_bubble_count<-gam(no_bio_reps_ampd_per_site ~ 
                  site_factor + 
                  s(calendar_month_number_mid, bs="cc"),
                  offset = no_bio_reps_collected_per_site, ## all are n = 10
                  method = "REML",
                  family = poisson(), ## suitable for count data
                  data = SHS_bubble_data)
## check diagnostics
print(check(getViz(gam_bubble_count)))

Method: REML   Optimizer: outer newton
full convergence after 3 iterations.
Gradient range [-1.664265e-06,-1.664265e-06]
(score 68.30349 & scale 1).
Hessian positive definite, eigenvalue range [0.4266786,0.4266786].
Model rank =  13 / 13 

Basis dimension (k) checking results. Low p-value (k-index<1) may
indicate that k is too low, especially if edf is close to k'.

                               k'  edf k-index p-value
s(calendar_month_number_mid) 8.00 4.06    0.94    0.49

summary_gbc<-summary(gam_bubble_count)
summary_gbc

Family: poisson 
Link function: log 

Formula:
no_bio_reps_ampd_per_site ~ site_factor + s(calendar_month_number_mid, 
    bs = "cc")

Parametric coefficients:
                         Estimate Std. Error z value Pr(>|z|)    
(Intercept)              -12.1776     0.7121 -17.100  < 2e-16 ***
site_factorInner Harbor    2.9479     0.7267   4.057 4.98e-05 ***
site_factorMiddle Shoals   0.3746     0.9134   0.410   0.6817    
site_factorOrote Point     0.3452     0.9132   0.378   0.7055    
site_factorSasa Bay        1.7609     0.7643   2.304   0.0212 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Approximate significance of smooth terms:
                               edf Ref.df Chi.sq p-value    
s(calendar_month_number_mid) 4.065      8   26.4  <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-sq.(adj) =  0.695   Deviance explained = 60.2%
-REML = 68.303  Scale est. = 1         n = 71
## Parametric coefficients:
knitr::kable(summary_gbc$p.table, digits = 4)
Estimate Std. Error z value Pr(>|z|)
(Intercept) -12.1776 0.7121 -17.1000 0.0000
site_factorInner Harbor 2.9479 0.7267 4.0567 0.0000
site_factorMiddle Shoals 0.3746 0.9134 0.4101 0.6817
site_factorOrote Point 0.3452 0.9132 0.3780 0.7055
site_factorSasa Bay 1.7609 0.7643 2.3038 0.0212

## Approximate significance of smooth terms:
knitr::kable(summary_gbc$s.table, digits = 4)
edf Ref.df Chi.sq p-value
s(calendar_month_number_mid) 4.065 8 26.4022 0
## visualise GAM results
print(draw(gam_bubble_count))

LS0tCnRpdGxlOiAiU0hTIHN1cnZleSByZXN1bHRzIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAotLS0KClFVRVNUSU9OOiBXaGVyZSBhbmQgd2hlbiBhcmUgU0hTIGluIEFwcmEgSGFyYm9yPwoKQUlNUzogQW5hbHlzZSBhbmQgcGxvdCBTSFMgZUROQSBkZXRlY3Rpb25zIGluIEJsdWUgSG9sZSwgSW5uZXIgSGFyYm9yLCBNaWRkbGUgU2hvYWxzLCBPcm90ZSBQb2ludCBhbmQgU2FzYSBCYXkgb3ZlciB0aGUgcGVyaW9kIG9mIEZlYiAyMDE5IHRvIEp1bHkgMjAyMC4gCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KY3VycmVudF9kaXJlY3RvcnkgPC0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRBY3RpdmVEb2N1bWVudENvbnRleHQoKSRwYXRoKQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpcj1ub3JtYWxpemVQYXRoKHBhc3RlKGN1cnJlbnRfZGlyZWN0b3J5KSkpCmBgYAoKYGBge3IgbG9hZF9saWJyYXJpZXMsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIExPQUQgTElCUkFSSUVTIC0tLS0KbGlicmFyeSh6b28pICMjIGFzLnllYXJtb24KbGlicmFyeShnZ21hcCkgIyMgbWFwcwpsaWJyYXJ5KGdnc24pICMjIHNjYWxlIGJhcgpsaWJyYXJ5KHZpcmlkaXMpICMjIGNvbG91ciBibGluZCBmcmllbmRseSBjb2xvdXIgc2NhbGUKbGlicmFyeShnZ3NwYXRpYWwpICMjIG5vcnRoIGFycm93CmxpYnJhcnkobWdjdikgIyMgR0FNCmxpYnJhcnkoZ3JhdGlhKSAjIyBhcyBhYm92ZQpsaWJyYXJ5KG1nY1ZpeikgIyMgZ2FtIGRpYWdub3N0aWNzCmxpYnJhcnkoZ2dwdWJyKSAjIyBnZ2FycmFuZ2UKbGlicmFyeSh0aWR5dmVyc2UpICMjIGxvYWQgbGFzdApgYGAKCgpgYGB7ciBTSFNfc3VydmV5X2RhdGEsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQojIyBJTVBPUlQgU0hTIFNVUlZFWSBEQVRBIC0tLS0KCiMjIGNvbG91ciBzY2hlbWUKIyBzY2FsZXM6OnNob3dfY29sKHZpcmlkaXMoNSkpCiMgc2NhbGVzOjpzaG93X2NvbCh2aXJpZGlzKDUsIGFscGhhPS44KSkKIyBzY2FsZXM6OnNob3dfY29sKHZpcmlkaXMoNCwgYWxwaGE9LjgsIG9wdGlvbj0iQiIpKQoKIyMgaW1wb3J0IHFQQ1IgcmVzdWx0cyAoYXMgY29uZmlybWVkIGJ5IHNhbmdlciBzZXF1ZW5jaW5nKQpTSFNfZGF0YV91bm1vZCA8LSByZWFkLmNzdigiZG9jcy8wMC4xX2NvbmZpcm1lZF9kZXRlY3Rpb25fZGF0YS5jc3YiKQoKIyMgaW1wb3J0IGZpZWxkIHNhbXBsZSBkYXRhIChpbmNsdWRpbmcgZUROQSBjb25jZW50cmF0aW9uKQpTSFNfZmllbGRfc2FtcGxlX2RhdGFfdW5tb2QgPC0gcmVhZC5jc3YoImRvY3MvMDAuMl9maWVsZF9zYW1wbGVfZGF0YS5jc3YiKQoKIyMgQ0FMQ1VMQVRFIFBST1BPUlRJT05TIC0tLS0KCiMjIGNhbGN1bGF0ZSB0aGUgcHJvcG9ydGlvbiBvZiB0ZWNobmljYWwgcmVwbGljYXRlcyBhbXBsaWZpZWQgcGVyIGJpb2xvZ2ljYWwgcmVwbGljYXRlIChlRE5BIHNhbXBsZSkKIyMgYW5kIHRoZSBwcm9wb3J0aW9uIG9mIGJpb2xvZ2ljYWwgcmVwbGljYXRlcyAoZUROQSBzYW1wbGVzKSBhbXBsaWZpZWQgcGVyIHNpdGUKU0hTX2RhdGE8LVNIU19kYXRhX3VubW9kICU+JQogICMjIGdyb3VwIGJ5IG1vbnRoLCBzaXRlIGFuZCBzYW1wbGUKICBncm91cF9ieShmaWVsZF9jb2xsZWN0aW9uX21vbnRoLCBzaXRlLCBzYW1wbGUpICU+JSAKICAjIyBhZGQgYSBjb2x1bW4gY29udGFpbmluZyB0aGUgdGVjaCByZXAgbnVtYmVyIAogIG11dGF0ZSh0ZWNoX3JlcF9ubyA9IHJvd19udW1iZXIoKSkgJT4lCiAgIyMgYWRkIGFuIHVud2VpZ2h0ZWQgdGFsbHkgb2YgdGhlIG51bWJlciBvZiByb3dzIHBlciBzYW1wbGUKICAjIyBpLmUuIHRoZSBudW1iZXIgb2YgdGVjaCByZXBzIHJ1biBwZXIgc2FtcGxlCiAgYWRkX3RhbGx5KG5hbWU9Im5vX3RlY2hfcmVwc19ydW5fcGVyX3NhbXBsZSIpICU+JSAKICAjIyBhZGQgYSB3ZWlnaHRlZCB0YWxseSBvZiB0aGUgbnVtYmVyIG9mIHJvd3Mgd2l0aCBhIHBvc2l0aXZlIHJlc3VsdAogICMjIGkuZS4gdGhlIG51bWJlciBvZiB0ZWNoIHJlcHMgYW1wbGlmaWVkIHBlciBzYW1wbGUKICBhZGRfdGFsbHkobmFtZT0ibm9fdGVjaF9yZXBzX2FtcGRfcGVyX3NhbXBsZSIsIHd0PXBvc2l0aXZlKSAlPiUgCiAgIyMgY2FsY3VsYXRlIHRoZSAgcHJvcCBvZiB0ZWNoIHJlcHMgYW1wbGlmaWVkIHBlciBzYW1wbGUKICBtdXRhdGUocHJvcF90ZWNoX3JlcHNfYW1wZF9wZXJfc2FtcGxlID0gCiAgICAgICAgICAgMS9ub190ZWNoX3JlcHNfcnVuX3Blcl9zYW1wbGUqbm9fdGVjaF9yZXBzX2FtcGRfcGVyX3NhbXBsZSkgJT4lCiAgIyMgY2FsY3VsYXRlIHRoZSBzYW1lIGluZm9ybWF0aW9uIGZvciBiaW9sb2dpY2FsIHJlcGxpY2F0ZXMKICBsZWZ0X2pvaW4oLiwgU0hTX2RhdGFfdW5tb2QgJT4lCiAgICAgICAgICAgICAgIyMgc2VsZWN0IG9ubHkgbmVjZXNzYXJ5IGluZm9ybWF0aW9uCiAgICAgICAgICAgICAgc2VsZWN0KHNhbXBsZSwgZmllbGRfY29sbGVjdGlvbl9tb250aCwgc2l0ZSwgcG9zaXRpdmUpICU+JQogICAgICAgICAgICAgICMjIGZpbHRlciBvdXQgYmxhbmtzCiAgICAgICAgICAgICAgZmlsdGVyKCFncmVwbCgnRScsIHNhbXBsZSkpICU+JQogICAgICAgICAgICAgICMjIHJldGFpbiBvbmx5IHVuaXF1ZSByb3dzIChyZW1vdmVzIHJvd3Mgd2hlcmUgbW9yZSB0aGFuIDEgdGVjaCByZXAgYW1wJ2QpCiAgICAgICAgICAgICAgdW5pcXVlKC4pICU+JQogICAgICAgICAgICAgICMjIGdyb3VwIGJ5IG1vbnRoIGFuZCBzaXRlCiAgICAgICAgICAgICAgZ3JvdXBfYnkoZmllbGRfY29sbGVjdGlvbl9tb250aCwgc2l0ZSkgJT4lCiAgICAgICAgICAgICAgIyMgYWRkIGEgd2VpZ2h0ZWQgdGFsbHkgb2YgdGhlIG51bWJlciBvZiByb3dzIHBlciBtb250aC9zaXRlIHcgcG9zaXRpdmUgcmVzdWx0cwogICAgICAgICAgICAgICMjIGkuZS4gdGhlIG51bWJlciBvZiBiaW9sb2dpY2FsIHJlcHMgYW1wbGlmaWVkIHBlciBzYW1wbGUKICAgICAgICAgICAgICBhZGRfdGFsbHkobmFtZT0ibm9fYmlvX3JlcHNfYW1wZF9wZXJfc2l0ZSIsIHd0PXBvc2l0aXZlKSAlPiUKICAgICAgICAgICAgICAjIyByZW1vdmUgcG9zaXRpdmUgY29sdW1uIChiZWNhdXNlIGl0IGRpZmZlcnMgYmV0d2VlbiBiaW8gcmVwcykKICAgICAgICAgICAgICBzZWxlY3QoLXBvc2l0aXZlKSAlPiUKICAgICAgICAgICAgICAjIyByZXRhaW4gb25seSB1bmlxdWUgcm93cyAocmVtb3ZlcyByb3dzIHdoZXJlIGluZm8gZGlmZmVycyB3aXRoaW4gc2FtcGxlKQogICAgICAgICAgICAgIHVuaXF1ZSguKSAlPiUKICAgICAgICAgICAgICAjIyBhZGQgYW4gdW53ZWlnaHRlZCB0YWxseSBvZiB0aGUgbnVtYmVyIG9mIHJvd3MgcGVyIHNpdGUKICAgICAgICAgICAgICAjIyBpLmUuIHRoZSBudW1iZXIgb2YgYmlvbG9naWNhbCByZXBzIGNvbGxlY3RlZCBwZXIgc2l0ZQogICAgICAgICAgICAgIGFkZF90YWxseShuYW1lPSJub19iaW9fcmVwc19jb2xsZWN0ZWRfcGVyX3NpdGUiKSAlPiUKICAgICAgICAgICAgICAjIyBjYWxjdWxhdGUgdGhlIHByb3Agb2YgYmlvbG9naWNhbCByZXBzIGFtcGxpZmllZCBwZXIgc2l0ZQogICAgICAgICAgICAgIG11dGF0ZShwcm9wX2Jpb19yZXBzX2FtcGRfcGVyX3NpdGUgPQogICAgICAgICAgICAgICAgICAgICAgIDEvbm9fYmlvX3JlcHNfY29sbGVjdGVkX3Blcl9zaXRlKm5vX2Jpb19yZXBzX2FtcGRfcGVyX3NpdGUpLAogICAgICAgICAgICAjIyBzcGVjaWZ5IGNvbHVtbnMgdG8gam9pbiBieQogICAgICAgICAgICBieSA9IGMoInNhbXBsZSIsICJmaWVsZF9jb2xsZWN0aW9uX21vbnRoIiwgInNpdGUiKSkgCgojIyBNRVJHRSBERVRFQ1RJT05TIEFORCBTQU1QTEUgREFUQSBBTkQgQUREIFRJTUUgT0YgWUVBUiBJTkZPIC0tLS0KU0hTX2RhdGFfZnVsbCA8LSBsZWZ0X2pvaW4oU0hTX2RhdGEsIFNIU19maWVsZF9zYW1wbGVfZGF0YV91bm1vZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygic2FtcGxlIiwgImZpZWxkX2NvbGxlY3Rpb25fbW9udGgiLCAic2l0ZSI9InNpdGVfbmFtZSIpKSAlPiUKICAjIyByZW5hbWUgZGF0IGNvbHVtbgogIHJlbmFtZShkYXRlX2NvbGxlY3RlZD1kYXRlKSAlPiUKICAjIyB1bmdyb3VwIGRhdGEKICB1bmdyb3VwKC4pICU+JQogICMjIGZvcm1hdCBmaWVsZCBjb2xsZWN0aW9uIG1vbnRoIGNvbHVtbgogIG11dGF0ZShmaWVsZF9jb2xsZWN0aW9uX21vbnRoID0gYXMueWVhcm1vbihmaWVsZF9jb2xsZWN0aW9uX21vbnRoKSkgJT4lCiAgIyMgYXJyYW5nZSByb3dzIGJ5IGZpZWxkIGNvbGxlY3Rpb24gbW9udGggY29sdW1uIHZhbHVlcwogIGFycmFuZ2UoLiwgZmllbGRfY29sbGVjdGlvbl9tb250aCkgJT4lCiAgIyMgYWRkIGFuZCBmb3JtYXQgZXh0cmEgZGF0ZSBpbmZvcm1hdGlvbiBjb2x1bW5zCiAgbXV0YXRlKGZjX21vbnRoX2ZhY3RvciA9IGZjdF9pbm9yZGVyKGZhY3RvcihmaWVsZF9jb2xsZWN0aW9uX21vbnRoKSksCiAgICAgICAgIGZjX21vbnRoX251bWJlciA9IGFzLm51bWVyaWMoZmFjdG9yKGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpKSwKICAgICAgICAgY2FsZW5kYXJfbW9udGggPSBmb3JtYXQoYXMueWVhcm1vbihmaWVsZF9jb2xsZWN0aW9uX21vbnRoKSwgIiVCIiksCiAgICAgICAgIGNhbGVuZGFyX21vbnRoX251bWJlciA9IGFzLm51bWVyaWMoZm9ybWF0KGZpZWxkX2NvbGxlY3Rpb25fbW9udGgsICIlbSIpKSwKICAgICAgICAgZmNfbW9udGhfbnVtYmVyX2N5Y2xpYyA9IGlmZWxzZShjYWxlbmRhcl9tb250aF9udW1iZXIgPiAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWxlbmRhcl9tb250aF9udW1iZXItMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FsZW5kYXJfbW9udGhfbnVtYmVyKzEwKSwKICAgICAgICAgIyMgYWRkIHNlYXNvbnMgdG8gZGF0YSBmcmFtZSAoZHJ5ID0gRGVjZW1iZXIgdG8gTWF5LCB3ZXQgPSBKdW5lIHRvIE5vdmVtYmVyKQogICAgICAgICBzZWFzb24gPSBpZmVsc2UoZ3JlcGwoIkRlYyIsIGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpLCAid2V0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAjIyBEZWMgPSB0cmFuc2l0aW9uYWwgbW9udGgKICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkphbiIsIGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpLCAiZHJ5IiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiRmViIiwgZmllbGRfY29sbGVjdGlvbl9tb250aCksICJkcnkiLAogICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIk1hciIsIGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpLCAiZHJ5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkFwciIsIGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpLCAiZHJ5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiTWF5IiwgZmllbGRfY29sbGVjdGlvbl9tb250aCksICJkcnkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkp1biIsIGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpLCAiZHJ5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBKdW4gPSB0cmFuc2l0aW9uYWwgbW9udGgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkp1bCIsIGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpLCAid2V0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiQXVnIiwgZmllbGRfY29sbGVjdGlvbl9tb250aCksICJ3ZXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIlNlcCIsIGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpLCAid2V0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIk9jdCIsIGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpLCAid2V0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIk5vdiIsIGZpZWxkX2NvbGxlY3Rpb25fbW9udGgpLCAid2V0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb25lIikpKSkpKSkpKSkpKSwKICAgICAgICAgc2Vhc29uX2ZhY3RvciA9IGZhY3RvcihzZWFzb24pKSAlPiUKICAjIyBhcnJhbmdlIGRhdGEgYnkgY2FsZW5kYXIgbW9udGggbnVtYmVyCiAgYXJyYW5nZSguLCBjYWxlbmRhcl9tb250aF9udW1iZXIpICU+JQogICMjIHJlb3JkZXIgZmFjdG9yIGxldmVscyBieSBmaXJzdCBhcHBlYXJhbmNlCiAgbXV0YXRlKGNhbGVuZGFyX21vbnRoX2ZhY3RvciA9IGZjdF9pbm9yZGVyKGZhY3RvcihjYWxlbmRhcl9tb250aCkpKSAlPiUKICAjIyByZW5hbWUgInBvc2l0aXZlIiBjb2x1bW4gdG8gaW5kaWNhdGUgdGVjaCByZXAgd2FzIHBvc2l0aXZlCiAgcmVuYW1lKHBvc2l0aXZlX3RlY2ggPSBwb3NpdGl2ZSkgJT4lCiAgIyMgYWRkIGEgcG9zaXRpdmUgYmlvIGNvbHVtbiB0byBpbmRpY2F0ZSBiaW8gcmVwIGlzIGNvbnNpZGVyZWQgcG9zaXRpdmUKICBtdXRhdGUocG9zaXRpdmVfYmlvID0gaWZlbHNlKG5vX3RlY2hfcmVwc19hbXBkX3Blcl9zYW1wbGUgPiAwLCAxLCAwKSkgJT4lCiAgIyMgc3RhcnQgbWlkIHllYXIKICBtdXRhdGUoY2FsZW5kYXJfbW9udGhfZmFjdG9yX21pZCA9IGZhY3RvcihjYWxlbmRhcl9tb250aF9mYWN0b3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiSnVseSIsICJBdWd1c3QiLCAiU2VwdGVtYmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9jdG9iZXIiLCAiTm92ZW1iZXIiLCAiRGVjZW1iZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSmFudWFyeSIgLCAiRmVicnVhcnkiLCAiTWFyY2giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXByaWwiLCAiTWF5IiwgIkp1bmUiKSkpCgojIyBleHBvcnQgaXQKd3JpdGUuY3N2KFNIU19kYXRhX2Z1bGwsICJkb2NzLzAxLjBfU0hTX2RhdGFfZnVsbC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCiMjIGV4dHJhY3QgYWxsIHBvaW50cyAod2hlcmUgcmVjb3JkZWQpIGZvciBmaWx0ZXIgc2FtcGxlIGVhY2ggc2l0ZS9tb250aApzYW1wbGluZ19wb2ludHM8LVNIU19maWVsZF9zYW1wbGVfZGF0YV91bm1vZCAlPiUKICBmaWx0ZXIobGF0aXR1ZGUhPSJOQSIgfCBsb25naXR1ZGUhPSJOQSIpICU+JSAKICBmaWx0ZXIobGF0aXR1ZGU8MTMuNDgpICU+JSAjIGJsdWUgaG9sZSBwb2ludCBub3QgYXQgYmx1ZSBob2xlCiAgbXV0YXRlKGZpZWxkX2NvbGxlY3Rpb25fbW9udGg9YXMueWVhcm1vbihmaWVsZF9jb2xsZWN0aW9uX21vbnRoKSkgJT4lCiAgc2VsZWN0KHNpdGVfbmFtZSwgZmllbGRfY29sbGVjdGlvbl9tb250aCwgc2FtcGxlX25vLCBsYXRpdHVkZSwgbG9uZ2l0dWRlKQoKIyMgZXh0cmFjdCBwb2ludHMgZm9yIGZpcnN0IGZpbHRlciBzYW1wbGUgZWFjaCBzaXRlL21vbnRoCmZpcnN0X3NhbXBsaW5nX3BvaW50cyA8LSBzYW1wbGluZ19wb2ludHMgJT4lCiAgZmlsdGVyKC4sIHNhbXBsZV9ubyA9PSAiMSIpICMgcmV0YWluIG9ubHkgZmlyc3Qgc2FtcGxlIChhbmQgR1BTIHBvaW50IGZvciB0aGF0IHNhbXBsZSkKCiMjIGV4cG9ydCB0aGVtIAp3cml0ZS5jc3Yoc2FtcGxpbmdfcG9pbnRzLCAiZG9jcy8wMS4xX3NhbXBsaW5nX3BvaW50cy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKd3JpdGUuY3N2KGZpcnN0X3NhbXBsaW5nX3BvaW50cyAsICJkb2NzLzAxLjJfZmlyc3Rfc2FtcGxpbmdfcG9pbnRzLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCmBgYHtyIFNIU19zdXJ2ZXlfbWFwcywgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZpZy53aWR0aCA9IDEyLCBmaWd1cmUuaGVpZ2h0ID0gMjB9CiMjIElNUE9SVCBMSUJSQVJJRVMgQU5EIE1BUCBEQVRBIC0tLS0KCiMjIHByb3ZpZGUgZ2dtYXAgd2l0aCB5b3VyIGtleQojIHJlZ2lzdGVyX2dvb2dsZShrZXkgPSAiW3lvdXIga2V5IGhlcmVdIikgCgojIyBjcmVhdGUgZGF0YSBmcmFtZSBmb3Igc2l0ZSBsb2NhdGlvbnMKU0hTX3NpdGVzIDwtIGNiaW5kLmRhdGEuZnJhbWUoc2l0ZT1jKCJJbm5lciBIYXJib3IiLCAiU2FzYSBCYXkiLCAiTWlkZGxlIFNob2FscyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9yb3RlIFBvaW50IiwgIkJsdWUgSG9sZSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbV9sYXRpdHVkZT1jKDEzLjQzMTgxLCAxMy40NDc2OSwgMTMuNDQ5NTksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEzLjQ0OTQ3LCAxMy40MzYyNyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1fbG9uZ2l0dWRlPWMoMTQ0LjY3NTczLCAxNDQuNjc1MzcsIDE0NC42NTcyOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDE0NC42MjQ2NiwgMTQ0LjYyNzQxKSkKCiMjIEZPUk1BVCBTSFMgU1VSVkVZIERBVEEgRk9SIE1BUCAtLS0tCgojIyBjcmVhdGUgZGF0YSBmcmFtZSB3aXRoIHNpdGUtbGV2ZWwgZGV0ZWN0aW9uIGRhdGEgKHJlbGV2YW50IHRvIG1hcCkgb25seQpTSFNfZmlndXJlX21hcF9kYXRhIDwtIFNIU19kYXRhX2Z1bGwgJT4lCiAgIyMgYWRkIHNpdGUgbG9jYXRpb25zIHRvIGZ1bGwgZGF0YSBzZXQKICBsZWZ0X2pvaW4oLiwgU0hTX3NpdGVzLCBieT0ic2l0ZSIpICU+JQogICMjIHJldGFpbiBvbmx5IGluZm9ybWF0aW9uIHJlbGF0ZWQgdG8gYmlvbG9naWNhbCByZXBsaWNhdGVzIChzYW1wbGVzKQogIHNlbGVjdChmaWVsZF9jb2xsZWN0aW9uX21vbnRoLCBkYXRlX2NvbGxlY3RlZCwKICAgICAgICAgc2l0ZSwgbV9sYXRpdHVkZSwgbV9sb25naXR1ZGUsIGNhbGVuZGFyX21vbnRoX2ZhY3RvciwKICAgICAgICAgY2FsZW5kYXJfbW9udGhfZmFjdG9yX21pZCwgY2FsZW5kYXJfbW9udGhfbnVtYmVyLAogICAgICAgICBzYW1wbGVfbGVzcywgcHJvcF9iaW9fcmVwc19hbXBkX3Blcl9zaXRlLCAKICAgICAgICAgbm9fYmlvX3JlcHNfYW1wZF9wZXJfc2l0ZSwgc2Vhc29uKSAlPiUKICAjIyBmaWx0ZXIgb3V0IGJsYW5rcwogIGZpbHRlcighZ3JlcGwoJ0UnLCBzYW1wbGVfbGVzcykpICU+JQogICMjIGtlZXAgb25seSB1bmlxdWUgcm93cyAocmVtb3ZlIHRlY2ggcmVwIGluZm8pCiAgdW5pcXVlKC4pICU+JQogICMjIGdyb3VwIGJ5IG1vbnRoIGFuZCBzaXRlCiAgZ3JvdXBfYnkoY2FsZW5kYXJfbW9udGhfZmFjdG9yLCBzaXRlKSAlPiUKICAjIyBjYWxjdWxhdGUgbWVhbiBwcm9wb3J0aW9uIG9mIGJpb2xvZ2ljYWwgcmVwbGljYXRlcyBhbXBsaWZpZWQgCiAgIyMgKGJlY2F1c2Ugd2Ugc2FtcGxlZCBNYXkgYW5kIEp1bHkgb2YgMjAxOSBhbiAyMDIwKQogIG11dGF0ZShtZWFuX3Byb3BfYmlvX2FtcHMgPSBtZWFuKHByb3BfYmlvX3JlcHNfYW1wZF9wZXJfc2l0ZSksIAogICAgICAgICBtZWFuX25vX2Jpb19hbXBzID0gY2VpbGluZyhtZWFuKG5vX2Jpb19yZXBzX2FtcGRfcGVyX3NpdGUpKSwKICAgICAgICAgIyMgc3BlY2lmeSB0aGUgc2hhcGUgaXMgYW4gIngiIGlmIDAgYW5kIGEgImNpcmNsZSIgaWYgZWxzZQogICAgICAgICBzaGFwZXMgPSBpZl9lbHNlKG1lYW5fbm9fYmlvX2FtcHMgPT0gMCwgIjQiLCAiMjEiKSwgCiAgICAgICAgICMjIHNwZWNpZnkgbGFiZWwgYXMgbm90aGluZyBpZiAwIGFuZCB0aGUgcHJvcG9ydGlvbiByb3VuZGVkIHRvIDEgZGlnaXQgaWYgZWxzZQogICAgICAgICBsYWJlbHMgPSBpZl9lbHNlKG1lYW5fbm9fYmlvX2FtcHMgPT0gMCwgIiAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShtZWFuX25vX2Jpb19hbXBzKSkpICU+JQogICMjIHJlbW92ZSBkdXBsaWNhdGUgbW9udGgsIHllYXIgYW5kIHNhbXBsZSBpbmZvCiAgc2VsZWN0KC1wcm9wX2Jpb19yZXBzX2FtcGRfcGVyX3NpdGUsIC1ub19iaW9fcmVwc19hbXBkX3Blcl9zaXRlLAogICAgICAgICAtZmllbGRfY29sbGVjdGlvbl9tb250aCwgLWRhdGVfY29sbGVjdGVkLCAtc2FtcGxlX2xlc3MpICU+JQogIHVuaXF1ZSguKSAlPiUKICAjIyBmb3Igc2NhbGVfYmFyCiAgbXV0YXRlKGxvbmcgPSBtX2xvbmdpdHVkZSwgbGF0ID0gbV9sYXRpdHVkZSkKCiMjIE1BS0UgQSBNQVAgLS0tLQoKIyAjIyBGaW5kIGxhdGl0dWRlcyBhbmQgbG9uZ2l0dWRlcyB0byBiZSBjZW50cmUgb2YgZGlzdHJpYnV0aW9uIG1hcAojIG1lYW4oU0hTX3NpdGVzJG1fbGF0aXR1ZGUpICMgMTMuNDQyOTcKIyBtZWFuKFNIU19zaXRlcyRtX2xvbmdpdHVkZSkgIyAxNDQuNjUyMQoKIyMgY3JlYXRlIG1hcCBzdHlsZSBhdCBodHRwczovL21hcHN0eWxlLndpdGhnb29nbGUuY29tLwpzMjwtICJzdHlsZT1lbGVtZW50Omdlb21ldHJ5JTdDY29sb3I6MHhmNWY1ZjUmc3R5bGU9ZWxlbWVudDpsYWJlbHMlN0N2aXNpYmlsaXR5Om9mZiZzdHlsZT1lbGVtZW50OmxhYmVscy5pY29uJTdDdmlzaWJpbGl0eTpvZmYmc3R5bGU9ZWxlbWVudDpsYWJlbHMudGV4dC5maWxsJTdDY29sb3I6MHg2MTYxNjEmc3R5bGU9ZWxlbWVudDpsYWJlbHMudGV4dC5zdHJva2UlN0Njb2xvcjoweGY1ZjVmNSZzdHlsZT1mZWF0dXJlOmFkbWluaXN0cmF0aXZlJTdDZWxlbWVudDpnZW9tZXRyeSU3Q3Zpc2liaWxpdHk6b2ZmJnN0eWxlPWZlYXR1cmU6YWRtaW5pc3RyYXRpdmUubGFuZF9wYXJjZWwlN0N2aXNpYmlsaXR5Om9mZiZzdHlsZT1mZWF0dXJlOmFkbWluaXN0cmF0aXZlLmxhbmRfcGFyY2VsJTdDZWxlbWVudDpsYWJlbHMudGV4dC5maWxsJTdDY29sb3I6MHhiZGJkYmQmc3R5bGU9ZmVhdHVyZTphZG1pbmlzdHJhdGl2ZS5uZWlnaGJvcmhvb2QlN0N2aXNpYmlsaXR5Om9mZiZzdHlsZT1mZWF0dXJlOnBvaSU3Q3Zpc2liaWxpdHk6b2ZmJnN0eWxlPWZlYXR1cmU6cG9pJTdDZWxlbWVudDpnZW9tZXRyeSU3Q2NvbG9yOjB4ZWVlZWVlJnN0eWxlPWZlYXR1cmU6cG9pJTdDZWxlbWVudDpsYWJlbHMudGV4dC5maWxsJTdDY29sb3I6MHg3NTc1NzUmc3R5bGU9ZmVhdHVyZTpwb2kucGFyayU3Q2VsZW1lbnQ6Z2VvbWV0cnklN0Njb2xvcjoweGU1ZTVlNSZzdHlsZT1mZWF0dXJlOnBvaS5wYXJrJTdDZWxlbWVudDpsYWJlbHMudGV4dC5maWxsJTdDY29sb3I6MHg5ZTllOWUmc3R5bGU9ZmVhdHVyZTpyb2FkJTdDdmlzaWJpbGl0eTpvZmYmc3R5bGU9ZmVhdHVyZTpyb2FkJTdDZWxlbWVudDpnZW9tZXRyeSU3Q2NvbG9yOjB4ZmZmZmZmJnN0eWxlPWZlYXR1cmU6cm9hZCU3Q2VsZW1lbnQ6bGFiZWxzLmljb24lN0N2aXNpYmlsaXR5Om9mZiZzdHlsZT1mZWF0dXJlOnJvYWQuYXJ0ZXJpYWwlN0NlbGVtZW50OmxhYmVscy50ZXh0LmZpbGwlN0Njb2xvcjoweDc1NzU3NSZzdHlsZT1mZWF0dXJlOnJvYWQuaGlnaHdheSU3Q2VsZW1lbnQ6Z2VvbWV0cnklN0Njb2xvcjoweGRhZGFkYSZzdHlsZT1mZWF0dXJlOnJvYWQuaGlnaHdheSU3Q2VsZW1lbnQ6bGFiZWxzLnRleHQuZmlsbCU3Q2NvbG9yOjB4NjE2MTYxJnN0eWxlPWZlYXR1cmU6cm9hZC5sb2NhbCU3Q2VsZW1lbnQ6bGFiZWxzLnRleHQuZmlsbCU3Q2NvbG9yOjB4OWU5ZTllJnN0eWxlPWZlYXR1cmU6dHJhbnNpdCU3Q3Zpc2liaWxpdHk6b2ZmJnN0eWxlPWZlYXR1cmU6dHJhbnNpdC5saW5lJTdDZWxlbWVudDpnZW9tZXRyeSU3Q2NvbG9yOjB4ZTVlNWU1JnN0eWxlPWZlYXR1cmU6dHJhbnNpdC5zdGF0aW9uJTdDZWxlbWVudDpnZW9tZXRyeSU3Q2NvbG9yOjB4ZWVlZWVlJnN0eWxlPWZlYXR1cmU6d2F0ZXIlN0NlbGVtZW50Omdlb21ldHJ5JTdDY29sb3I6MHhjOWM5Yzkmc3R5bGU9ZmVhdHVyZTp3YXRlciU3Q2VsZW1lbnQ6bGFiZWxzLnRleHQuZmlsbCU3Q2NvbG9yOjB4OWU5ZTllJnNpemU9NDgweDM2MCIKCiMjIGdldCBhIEdvb2dsZSBtYXAgb2YgQXByYSBIYXJib3IgKHJldHJpZXZlcyByYXN0ZXIgbWFwIGZyb20gR29vZ2xlIE1hcHMpCiMjIE5vdGUgdGhhdCBpbiBtb3N0IGNhc2VzIGJ5IHVzaW5nIHRoaXMgZnVuY3Rpb24geW91IGFyZSBhZ3JlZWluZyB0byB0aGUgR29vZ2xlIE1hcHMgQVBJIFRlcm1zIG9mIFNlcnZpY2UgYXQgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL21hcHMtcGxhdGZvcm0vdGVybXMvICoqCkFwcmFIYXJib3IgPC0gZ2V0X2dvb2dsZW1hcChjZW50ZXIgPSBjKGxvbiA9IDE0NC42NTIxLCBsYXQgPSAxMy40NDI5NyksIAogICAgICAgICAgICAgICAgem9vbSA9IDEzLCAKICAgICAgICAgICAgICAgIG1hcHR5cGUgPSAndGVycmFpbicsCiAgICAgICAgICAgICAgICBjb2xvciA9ICdidycsCiAgICAgICAgICAgICAgICBzdHlsZSA9IHMyKQoKIyMgdXNlIGdnbWFwIHRvIHBsb3QgdGhlIHRoZSByYXN0ZXIgdXNpbmcgdGhlIGdncGxvdDIgZnJhbWV3b3JrCmdnbWFwKEFwcmFIYXJib3IpCgojIyBhZGQgU0hTIHN1cnZleSBpbmZvcm1hdGlvbiB0byBwbG90Cm1hcDEuMCA8LSBnZ21hcChBcHJhSGFyYm9yLCBleHRlbnQgPSAicGFuZWwiKSArCiAgIyMgc3BlY2lmeSB0aGUgYWVzdGhldGljcyBvZiB0aGUgImJ1YmJsZXMiIG9uIHRoZSBwbG90CiAgZ2VvbV9wb2ludChhZXMoeCA9IG1fbG9uZ2l0dWRlLCB5ID0gbV9sYXRpdHVkZSwgCiAgICAgICAgICAgICAgICAgZmlsbCA9IHNpdGUsCiAgICAgICAgICAgICAgICAgc2l6ZSA9IG1lYW5fbm9fYmlvX2FtcHMsIHNoYXBlID0gc2hhcGVzKSwgCiAgICAgICAgICAgICBkYXRhID0gU0hTX2ZpZ3VyZV9tYXBfZGF0YSwKICAgICAgICAgICAgIGFscGhhID0gMC42LCAKICAgICAgICAgICAgIHN0cm9rZSA9IDAuNikgKwogICMjIGN1c3RvbWlzZSB0aGUgc2l6ZQogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDIsIDEyKSwgZ3VpZGUgPSAibm9uZSIpICsgCiAgIyMgY3VzdG9taXNlIHRoZSBzaGFwZSBzbyB0aGF0IDAgdmFsdWVzIGFyZSAieCIKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjEsIDQpLCBndWlkZSA9ICJub25lIikgKwogICMgbGltaXQgdGhlIHNpemUgb2YgdGhlIHBsb3QgKHByb2R1Y2VzIG1lc3NhZ2UsIGlnbm9yZSBpdCkKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygxNDQuNjE1LCAxNDQuNjkpLCBleHBhbmQgPSBjKDAsIDApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMTMuNDE1LCAxMy40NyksIGV4cGFuZCA9IGMoMCwgMCkpICsKICB4bGFiKCJMb25naXR1ZGUiKSsKICB5bGFiKCJMYXRpdHVkZSIpKwogICMjIGZhY2V0IHRoZSBwbG90IGJ5IG1vbnRoIChuPTIgZm9yIE1heSBhbmQgSnVseSkKICBmYWNldF93cmFwKH4gY2FsZW5kYXJfbW9udGhfZmFjdG9yX21pZCwgbmNvbCA9IDMpICsKICAjIyBtb3ZlIHRoZSBsZWdlbmQgYW5kIGVkaXQgdGhlIGZhY2V0IHN0cmlwIHBhbmVscwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwgCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmF5MzAiLCBmaWxsID0gTkEpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4oMC4xLCAwLCAwLjEsIDAsICJjbSIpKSkgKwogICMjIG1ha2UgaXQgY29sb3VyIGJsaW5kIGZyaWVuZGx5CiAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlPVRSVUUpICsKICAjIyBlZGl0IGxlZ2VuZCBhcHBlYXJhbmNlCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaGFwZSA9IDIxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIlNpdGUiKSkgKwogICMjIGFkZCBsYWJlbHMgdG8gImJ1YmJsZXMiCiAgZ2VvbV90ZXh0KGFlcyh4ID0gbV9sb25naXR1ZGUsIHkgPSBtX2xhdGl0dWRlLCAKICAgICAgICAgICAgICAgIGxhYmVsID0gbGFiZWxzLCAKICAgICAgICAgICAgICAgIHNpemUgPSAwLjEpLAogICAgICAgICAgICBkYXRhID0gU0hTX2ZpZ3VyZV9tYXBfZGF0YSkKCiMgbWFwMS4wCgojIHBsb3QubmV3KCkgIyMgdXNlIHRoaXMgaWYgeW91IGdldCBhbiBlcnJvciBiZWxvdwoKIyMgYWRkIGEgc2NhbGUgYmFyCm1hcDEuMiA8LSBtYXAxLjAgKyBzY2FsZWJhcihkYXRhID0gU0hTX2ZpZ3VyZV9tYXBfZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3Q9MC41LCAjIGRpc3RhbmNlIHRvIHJlcHJlc2VudCBlYWNoIHNlZ21lbnQgb2YgdGhlIHNjYWxlIGJhciAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RfdW5pdD0ia20iLCAjIHVuaXQgb2YgbWVhc3VyZW1lbnQgZm9yIGRpc3QKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT1UUlVFLCAjIFRSVUUgPSBkZWNpbWFsIGRlZ3JlZXMsIEZBTFNFID0gbQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSAnV0dTODQnLCAjIGNob2ljZSBvZiBlbGxpcHNvaWRlIG1vZGVsICh3aGVyZSB0cmFuc29ybT1UUlVFKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyLnNpemUgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3guY29sb3IgPSAiZ3JleTMwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJveC5maWxsID0gYygiZ3JleTgwIiwgIndoaXRlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdC5zaXplID0gMiwgIyMgc2NhbGUgYmFyIHNpemUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSAwLjA5LCAjIyBoZWlnaHQgYXMgcHJvcG9ydGlvbiBvZiB0aGUgeS1heGlzICgwLTEpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbiA9ICJib3R0b21yaWdodCIsICMjIHNjYWxlIGJhcnMgbG9jYXRpb24gaW4gdGhlIHBsb3QKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuY2hvciA9IGMoeD0xNDQuNjg4LHk9MTMuNDE3KSwgIyMgZm9yIGNvcm5lciBvZiBsb2NhdGlvbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3QuZGlzdCA9IDAuMSwgIyMgZGlzdGFuY2UgYncgc2NhbGUgYmFyIGFuZCB0ZXh0CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAgIyMgbWFrZSB0aGUgdGV4dCBzZWUtdGhyb3VnaAogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAKIyBtYXAxLjIKCiMjIGFkZCBub3J0aCBhcnJvdwptYXAxLjMgPC0gbWFwMS4yICsgIAogIGFubm90YXRpb25fbm9ydGhfYXJyb3coaGVpZ2h0ID0gdW5pdCgwLjI1LCAiY20iKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoID0gdW5pdCgwLjI1LCJjbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb24gPSAidGwiLCAjIyB0b3AgbGVmdAogICAgICAgICAgICAgICAgICAgICAgICAgcGFkX3ggPSB1bml0KDAuMjUsICJjbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFkX3kgPSB1bml0KDAuMjUsICJjbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGUgPSBub3J0aF9hcnJvd19vcmllbnRlZXJpbmcoCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVfd2lkdGggPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5lX2NvbCA9ICJncmF5NTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gYygiZ3JheTgwIiwgIndoaXRlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHRfY29sID0gTkEsICMjIHJlbW92ZXMgdGV4dD8KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dF9mYW1pbHkgPSAiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dF9mYWNlID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dF9zaXplID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dF9hbmdsZSA9IDApKQptYXAxLjMKIyMgc2F2ZSBpdApnZ3NhdmUoImRvY3MvZmlndXJlX2RldGVjdC50aWZmIiwgcGxvdD1tYXAxLjMsIGRldmljZT0idGlmZiIsIHdpZHRoPTIxLzEuMiwgaGVpZ2h0PTI4LzEuMiwgdW5pdHM9ImNtIiwgZHBpPTUwMCkKYGBgCgpgYGB7ciBidWJibGVfcGxvdF9zdGF0c30KIyMgRk9STUFUIFNIUyBEQVRBIEZPUiBCVUJCTEUgUExPVCBNT0RFTCAtLS0tCiMjIGNyZWF0ZSBkYXRhIGZyYW1lIHdpdGggc2l0ZS1sZXZlbCBkZXRlY3Rpb24gZGF0YSAocmVsZXZhbnQgdG8gbW9kZWwpIG9ubHkKU0hTX2J1YmJsZV9kYXRhIDwtIFNIU19kYXRhX2Z1bGwgJT4lCiAgIyMgZmlsdGVyIG91dCBibGFua3MKICBmaWx0ZXIoIWdyZXBsKCdFJywgc2FtcGxlX2xlc3MpKSAlPiUKICAjIyByZXRhaW4gb25seSBpbmZvcm1hdGlvbiBhdCB0aGUgc2l0ZS1sZXZlbAogIHNlbGVjdChmaWVsZF9jb2xsZWN0aW9uX21vbnRoLCBmY19tb250aF9mYWN0b3IsIGZjX21vbnRoX251bWJlciwKICAgICAgICAgZmNfbW9udGhfbnVtYmVyX2N5Y2xpYywgY2FsZW5kYXJfbW9udGgsIGNhbGVuZGFyX21vbnRoX2ZhY3RvciwKICAgICAgICAgY2FsZW5kYXJfbW9udGhfZmFjdG9yX21pZCwgY2FsZW5kYXJfbW9udGhfbnVtYmVyLCBkYXRlX2NvbGxlY3RlZCwgCiAgICAgICAgIHNpdGUsIHNlYXNvbiwgc2Vhc29uX2ZhY3RvciwgcHJvcF9iaW9fcmVwc19hbXBkX3Blcl9zaXRlLCAKICAgICAgICAgbm9fYmlvX3JlcHNfYW1wZF9wZXJfc2l0ZSwgbm9fYmlvX3JlcHNfY29sbGVjdGVkX3Blcl9zaXRlKSAlPiUKICAjIyBrZWVwIG9ubHkgdW5pcXVlIHJvd3MgKHJlbW92ZSB0ZWNoIHJlcCBpbmZvKQogIHVuaXF1ZSguKSAlPiUKICBtdXRhdGUoc2l0ZV9mYWN0b3I9ZmFjdG9yKHNpdGUpKSAlPiUKICAjIyBjcmVhdGUgbmV3IGNhbGVuZGFyIG1vbnRoIG51bWJlciBjb2x1bW4gCiAgbXV0YXRlKGNhbGVuZGFyX21vbnRoX251bWJlcl9taWQgPSBhcy5udW1lcmljKGNhbGVuZGFyX21vbnRoX2ZhY3Rvcl9taWQpKQoKIyMgZXhwb3J0IGl0CndyaXRlLmNzdihTSFNfYnViYmxlX2RhdGEsICJkb2NzLzAxLjNfU0hTX2J1YmJsZV9kYXRhLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKIyMgTU9ERUwgREFUQSBXSVRIIEdBTSAtLS0tCmdhbV9idWJibGVfY291bnQ8LWdhbShub19iaW9fcmVwc19hbXBkX3Blcl9zaXRlIH4gCiAgICAgICAgICAgICAgICAgIHNpdGVfZmFjdG9yICsgCiAgICAgICAgICAgICAgICAgIHMoY2FsZW5kYXJfbW9udGhfbnVtYmVyX21pZCwgYnM9ImNjIiksCiAgICAgICAgICAgICAgICAgIG9mZnNldCA9IG5vX2Jpb19yZXBzX2NvbGxlY3RlZF9wZXJfc2l0ZSwgIyMgYWxsIGFyZSBuID0gMTAKICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIlJFTUwiLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKCksICMjIHN1aXRhYmxlIGZvciBjb3VudCBkYXRhCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBTSFNfYnViYmxlX2RhdGEpCiMjIGNoZWNrIGRpYWdub3N0aWNzCnByaW50KGNoZWNrKGdldFZpeihnYW1fYnViYmxlX2NvdW50KSkpCnN1bW1hcnlfZ2JjPC1zdW1tYXJ5KGdhbV9idWJibGVfY291bnQpCnN1bW1hcnlfZ2JjCgojIyBQYXJhbWV0cmljIGNvZWZmaWNpZW50czoKa25pdHI6OmthYmxlKHN1bW1hcnlfZ2JjJHAudGFibGUsIGRpZ2l0cyA9IDQpCgojIyBBcHByb3hpbWF0ZSBzaWduaWZpY2FuY2Ugb2Ygc21vb3RoIHRlcm1zOgprbml0cjo6a2FibGUoc3VtbWFyeV9nYmMkcy50YWJsZSwgZGlnaXRzID0gNCkKYGBgCgpgYGB7ciB2aXN1YWxpc2VfR0FNLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gOX0KIyMgdmlzdWFsaXNlIEdBTSByZXN1bHRzCnByaW50KGRyYXcoZ2FtX2J1YmJsZV9jb3VudCkpCmBgYAoKYGBge3IgdmlzdWFsaXNlX0dBTV9jdXN0b20sIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA5LCBpbmNsdWRlPUZBTFNFfQojIyBDVVNUT00gRFJBVyBHQU0gRlVOQ1RJT04gLS0tLQojIyBjcmVhdGUgYSBtb2RpZmllZCB2ZXJzaW9uIG9mIGdyYXRpYSdzIGRyYXcgZnVuY3Rpb24gdXNpbmcgY29kZSBmcm9tIE1hcmNvIFNhbmRyaQojIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy81NDg5MTgyMy9jYW5ub3QtdXBkYXRlLWVkaXQtZ2dwbG90Mi1vYmplY3QtZXhwb3J0ZWQtZnJvbS1hLXBhY2thZ2UtZ3JhdGlhLWluLXIKIyBjdXN0b21fZHJhdyA8LSBmdW5jdGlvbiAob2JqZWN0LCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1ldHJpYyA9IFRSVUUsIHNlbGVjdCA9IE5VTEwsIHNjYWxlcyA9IGMoImZyZWUiLCJmaXhlZCIpLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ24gPSAiaHYiLCBheGlzID0gImxydGIiLCBuID0gMTAwLCB1bmNvbmRpdGlvbmFsID0gRkFMU0UsIAojICAgICAgICAgICAgICAgICAgICAgICAgIG92ZXJhbGxfdW5jZXJ0YWludHkgPSBUUlVFLCBkaXN0ID0gMC4xLCAuLi4pIAojIHsKIyAgIHNjYWxlcyA8LSBtYXRjaC5hcmcoc2NhbGVzKQojICAgUyA8LSBzbW9vdGhzKG9iamVjdCkKIyAgIHNlbGVjdCA8LSBncmF0aWE6OjpjaGVja191c2VyX3NlbGVjdF9zbW9vdGhzKHNtb290aHMgPSBTLCBzZWxlY3QgPSBzZWxlY3QpCiMgICBkIDwtIGdyYXRpYTo6OnNtb290aF9kaW0ob2JqZWN0KQojICAgdGFrZSA8LSBkIDw9IDJMCiMgICBzZWxlY3QgPC0gc2VsZWN0W3Rha2VdCiMgICBTIDwtIFNbdGFrZV0KIyAgIGQgPC0gZFt0YWtlXQojICAgaXNfcmUgPC0gdmFwcGx5KG9iamVjdFtbInNtb290aCJdXSwgZ3JhdGlhOjo6aXNfcmVfc21vb3RoLCBsb2dpY2FsKDFMKSkKIyAgIGlzX2J5IDwtIHZhcHBseShvYmplY3RbWyJzbW9vdGgiXV0sIGdyYXRpYTo6OmlzX2J5X3Ntb290aCwgbG9naWNhbCgxTCkpCiMgICBpZiAoYW55KGlzX2J5KSkgewojICAgICBTIDwtIHZhcHBseShzdHJzcGxpdChTLCAiOiIpLCBgW1tgLCBjaGFyYWN0ZXIoMUwpLCAxTCkKIyAgIH0KIyAgIG5wYXJhIDwtIDAKIyAgIG5zbW9vdGggPC0gbGVuZ3RoKFMpCiMgICBpZiAoaXNUUlVFKHBhcmFtZXRyaWMpKSB7CiMgICAgIHRlcm1zIDwtIHBhcmFtZXRyaWNfdGVybXMob2JqZWN0KQojICAgICBucGFyYSA8LSBsZW5ndGgodGVybXMpCiMgICAgIHAgPC0gdmVjdG9yKCJsaXN0IiwgbGVuZ3RoID0gbnBhcmEpCiMgICB9CiMgICBnIDwtIGwgPC0gdmVjdG9yKCJsaXN0IiwgbGVuZ3RoID0gbnNtb290aCkKIyAgIGZvciAoaSBpbiB1bmlxdWUoUykpIHsKIyAgICAgZVMgPC0gZXZhbHVhdGVfc21vb3RoKG9iamVjdCwgc21vb3RoID0gaSwgbiA9IG4sIHVuY29uZGl0aW9uYWwgPSB1bmNvbmRpdGlvbmFsLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIG92ZXJhbGxfdW5jZXJ0YWludHkgPSBvdmVyYWxsX3VuY2VydGFpbnR5LCBkaXN0ID0gZGlzdCkKIyAgICAgbFtTID09IGldIDwtIHNwbGl0KGVTLCBlU1tbInNtb290aCJdXSkKIyAgIH0KIyAgIGwgPC0gbFtzZWxlY3RdCiMgICBkIDwtIGRbc2VsZWN0XQojICAgZyA8LSBnW3NlbGVjdF0KIyAgIGlmIChsZW5ndGgoZykgPT0gMEwpIHsKIyAgICAgbWVzc2FnZSgiVW5hYmxlIHRvIGRyYXcgYW55IG9mIHRoZSBtb2RlbCB0ZXJtcy4iKQojICAgICByZXR1cm4oaW52aXNpYmxlKGcpKQojICAgfQojICAgZm9yIChpIGluIHNlcV9hbG9uZyhsKSkgewojICAgICBnW1tpXV0gPC0gZHJhdyhsW1tpXV0pCiMgICB9CiMgICBpZiAoaXNUUlVFKHBhcmFtZXRyaWMpKSB7CiMgICAgIGZvciAoaSBpbiBzZXFfYWxvbmcodGVybXMpKSB7CiMgICAgICAgcFtbaV1dIDwtIGV2YWx1YXRlX3BhcmFtZXRyaWNfdGVybShvYmplY3QsIHRlcm0gPSB0ZXJtc1tpXSkKIyAgICAgICBnW1tpICsgbGVuZ3RoKGcpXV0gPC0gZHJhdyhwW1tpXV0pCiMgICAgIH0KIyAgIH0KIyAgIGlmIChpc1RSVUUoaWRlbnRpY2FsKHNjYWxlcywgImZpeGVkIikpKSB7CiMgICAgIHdyYXBwZXIgPC0gZnVuY3Rpb24oeCkgewojICAgICAgIHJhbmdlKHhbWyJlc3QiXV0gKyAoMiAqIHhbWyJzZSJdXSksIHhbWyJlc3QiXV0gLSAKIyAgICAgICAgICAgICAgICgyICogeFtbInNlIl1dKSkKIyAgICAgfQojICAgICB5bGltcyA8LSByYW5nZSh1bmxpc3QobGFwcGx5KGwsIHdyYXBwZXIpKSkKIyAgICAgaWYgKGlzVFJVRShwYXJhbWV0cmljKSkgewojICAgICAgIHlsaW1zIDwtIHJhbmdlKHlsaW1zLCB1bmxpc3QobGFwcGx5KHAsIGZ1bmN0aW9uKHgpIHJhbmdlKHhbWyJ1cHBlciJdXSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeFtbImxvd2VyIl1dKSkpKQojICAgICB9CiMgICAgIGdnIDwtIHNlcV9hbG9uZyhnKVtjKGQgPT0gMUwsIHJlcChUUlVFLCBucGFyYSkpXQojICAgICBmb3IgKGkgaW4gZ2cpIHsKIyAgICAgICBnW1tpXV0gPC0gZ1tbaV1dICsgbGltcyh5ID0geWxpbXMpCiMgICAgIH0KIyAgIH0KIyAgIGcKIyB9CiMgCiMgIyMgQ1VTVE9NIFBMT1QgLS0tLQojIHBsb3Q8LWN1c3RvbV9kcmF3KGdhbV9idWJibGVfY291bnQpCiMgCiMgcGxvdDE8LXBsb3RbWzFdXSArIAojICAgZ2d0aXRsZShOVUxMKSArIAojICAgeWxhYigiRWZmZWN0IG9mIG1vbnRoIikgKwojICAgeGxhYigiTW9udGgiKSArIAojICAgdGhlbWVfYncoKSArIAojICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKDEsIDEyKSwgCiMgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzPXNlcSgxLCAxMiwgYnk9MSksIAojICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIkp1bHkiLCAiQXVndXN0IiwgIiAgICAgU2VwdGVtYmVyIiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9jdG9iZXIiLCAiTm92ZW1iZXIiLCAiRGVjZW1iZXIiLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSmFudWFyeSIsICJGZWJydWFyeSIsICJNYXJjaCIsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBcHJpbCIsICJNYXkiLCAiSnVuZSIpKSArCiMgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0PSAxKSwgCiMgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLng9ZWxlbWVudF9ibGFuaygpKQojIAojIHBsb3QyPC1wbG90W1syXV0gKwojICAgeGxhYigiU2l0ZSIpICsKIyAgIHlsYWIoIlBhcnRpYWwgZWZmZWN0IG9mIHNpdGUiKSArCiMgICBnZ3RpdGxlKE5VTEwpKwojICAgdGhlbWVfYncoKSArCiMgICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz1jKCJCbHVlIEhvbGUiLCAiSW5uZXIgSGFyYm9yIiwgIk1pZGRsZSBTaG9hbHMiLCAiT3JvdGUgUG9pbnQiLCAiU2FzYSBCYXkiKSkrCiMgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0PSAxKSkrCiMgICBnZW9tX3BvaW50KGZpbGw9dmlyaWRpcyhuPTUpLCBzaXplPTMsIHNoYXBlPTIxLCBzdHJva2U9MC42KQojIAojICMjIHBsb3QgY3VzdG9tIGdhbSBwbG90IGZvciBwdWIKIyBHQU1fcGxvdDwtZ2dhcnJhbmdlKHBsb3QxLCBwbG90MiwgbGFiZWxzPWMoIkEiLCAiQiIpKQojIEdBTV9wbG90CiMgCiMgIyMgc2F2ZSBpdAojIGdnc2F2ZSgiZG9jcy9maWd1cmVfR0FNLnRpZmYiLCBwbG90PUdBTV9wbG90LCBkZXZpY2U9InRpZmYiLCB3aWR0aD0yMTAsIGhlaWdodD0yOTcvMywgdW5pdHM9Im1tIiwgZHBpPTUwMCkKYGBgCgoKCg==